package com.lizi.apidoc.builder;

import com.lizi.apidoc.constants.AnnotationKeyName;
import com.lizi.apidoc.constants.AnnotationName;
import com.lizi.apidoc.constants.DocTags;
import com.lizi.apidoc.handler.ReqHeaderHandler;
import com.lizi.apidoc.handler.RequestBaseInfoHandler;
import com.lizi.apidoc.handler.RequestParamHandler;
import com.lizi.apidoc.handler.ResponseParamHandler;
import com.lizi.apidoc.model.*;
import com.lizi.apidoc.utils.DocTagUtil;
import com.lizi.apidoc.utils.DocUtil;
import com.lizi.apidoc.utils.StringUtil;
import com.thoughtworks.qdox.model.JavaAnnotation;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaMethod;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.lizi.apidoc.utils.DocTagUtil.getTagValue;

/**
 * Api文档构造器
 *
 * @author kingman zhangjw@3vjia.com
 * @since 2020-05-07 11:34
 */
public class DocBuilder {

    private ApiConfig config;

    public DocBuilder(ApiConfig config)
    {
        this.config = config;
        ClassLoader.getInstance().init(config);
    }

    public List<ClassDoc> loadClassDocs()
    {

        List<ClassDoc> apiDocList = new ArrayList<>();
        int order = 0;
        for (JavaClass cls : ClassLoader.getInstance().getFilterPackageJavaClasses()) {
            ClassDoc doc = createDoc(cls);
            apiDocList.add(doc);
        }
        return apiDocList;

    }

    /**
     * 创建单个文档
     * @param cls
     * @return
     */
    private ClassDoc createDoc(JavaClass cls)
    {
        String controllerName = cls.getName();
        ClassDoc apiDoc = new ClassDoc();
        apiDoc.setName(controllerName);
        apiDoc.setDesc(cls.getComment());
        List<ClassMethodDoc> methodDocs = createMethodDoc(cls);
        apiDoc.setList(methodDocs);

        return apiDoc;
    }

    /**
     * 创建类的方法
     * @param cls
     * @return
     */
    private List<ClassMethodDoc> createMethodDoc(final JavaClass cls)
    {
        String clazName = cls.getCanonicalName();
        List<JavaAnnotation> classAnnotations = cls.getAnnotations();
        String baseUrl = "";
        for (JavaAnnotation annotation : classAnnotations) {
            String annotationName = annotation.getType().getName();
            if (AnnotationName.REQUEST_MAPPING.equals(annotationName)) {
                if (annotation.getNamedParameter(AnnotationKeyName.VALUE) != null) {
                    baseUrl = StringUtil.removeQuotes(annotation.getNamedParameter(AnnotationKeyName.VALUE).toString());
                }
            }
        }
        List<JavaMethod> methods = cls.getMethods();
        List<ClassMethodDoc> methodDocList = new ArrayList<>(methods.size());
        int methodOrder = 0;
        for (JavaMethod method : methods) {

            if (method.isPrivate()) {
                //私有方法
                continue;
            }

            methodOrder++;

            //region 基础信息
            ClassMethodDoc classMethodDoc = new ClassMethodDoc();
            classMethodDoc.setOrder(methodOrder);
            classMethodDoc.setDesc(method.getComment());
            classMethodDoc.setName(method.getName());
            classMethodDoc.setAuthor(getTagValue(method, DocTags.AUTHOR));
            String apiNoteValue = getTagValue(method, DocTags.API_NOTE);
            if (StringUtil.isNullOrEmpty(apiNoteValue)) {
                apiNoteValue = method.getComment();
            }
            classMethodDoc.setDetail(apiNoteValue);
            //endregion

            //region Header
            List<ApiReqHeader> apiReqHeaders = ReqHeaderHandler.builder().handle(method);
            classMethodDoc.setRequestHeaders(apiReqHeaders);
            //endregion

            RequestBaseInfo requestMapping = RequestBaseInfoHandler.builder().handle(config.getServerUrl(),baseUrl,method);

            if(requestMapping!=null){
                classMethodDoc.setType(requestMapping.getMethodType());
                classMethodDoc.setUrl(requestMapping.getUrl());
                classMethodDoc.setServerUrl(config.getServerUrl());
                classMethodDoc.setPath(requestMapping.getShortUrl());
                classMethodDoc.setDeprecated(requestMapping.isDeprecated());

                String className = method.getDeclaringClass().getCanonicalName();
                Map<String, String> paramTagMap = DocUtil.getParamsComments(method, DocTags.PARAM, className);
                if(paramTagMap==null){
                    paramTagMap = new HashMap<>();
                }
                classMethodDoc.setParamTagMap(paramTagMap);

                //region RequestBody
                List<ApiObjectProperty> requestBodyParams = RequestParamHandler.builder().handle(method, DocTags.PARAM);
                classMethodDoc.setRequestBody(requestBodyParams);
                //endregion

                //region RequestBody
                ApiObjectProperty responseBodyParams = ResponseParamHandler.builder().handle(method,getTagValue(method, DocTags.RETURN));
                classMethodDoc.setResponseBody(responseBodyParams);
                //endregion
            }

            methodDocList.add(classMethodDoc);
        }
        return methodDocList;
    }
}
